patch_list = []

try:
    from djongo.models import EmbeddedModelField
    from django.db.models.lookups import PatternLookup

    def process_rhs(self, qn, connection):
        rhs, params = super(PatternLookup, self).process_rhs(qn, connection)
        if isinstance(params[0], dict):
            field, to_match = next(iter(params[0].items()))
            params[0][field] = self.param_pattern % connection.ops.prep_for_like_query(to_match)
        return rhs, params

    def patch_get_lookup(self, lookup_name):
        """阻止django的LIKE查询把传入EmbeddedModelField的字典变成一个字符串"""
        lookup = super(self.__class__, self).get_lookup(lookup_name)
        if issubclass(lookup, PatternLookup):
            lookup = type('Djongo' + lookup.__name__, (lookup,), {'process_rhs': process_rhs})
        return lookup

    patch_list.append((EmbeddedModelField, 'get_lookup', patch_get_lookup))
except ImportError:
    pass

try:
    import django.contrib.auth.hashers as django_hashers

    def patch_identify_hasher(encoded):
        """
        由于django的identify_hasher方法不能识别{HASHER}base64这种格式的密码，我们需要对它打猴子补丁
        """
        # Ancient versions of Django created plain MD5 passwords and accepted
        # MD5 passwords with an empty salt.
        if ((len(encoded) == 32 and '$' not in encoded) or
                (len(encoded) == 37 and encoded.startswith('md5$$'))):
            algorithm = 'unsalted_md5'
        # Ancient versions of Django accepted SHA1 passwords with an empty salt.
        elif len(encoded) == 46 and encoded.startswith('sha1$$'):
            algorithm = 'unsalted_sha1'
        elif encoded.startswith('{MD5}'):
            algorithm = 'ldap_md5'
        elif encoded.startswith('{SHA}'):
            algorithm = 'ldap_sha1'
        else:
            algorithm = encoded.split('$', 1)[0]
        return django_hashers.get_hasher(algorithm)

    patch_list.append((django_hashers, 'identify_hasher', patch_identify_hasher))
except ImportError:
    pass


def monkey_patch():
    for obj, attr, patch in patch_list:
        setattr(obj, attr, patch)
